/*
Copyright (c) 2025, 北京智慧物联科技有限公司.

简体中文
保留所有权利。依据GPL 2.0（以下简称"本许可"）进行许可。除非符合（遵守）本许可及以下条款，否则您不得使用此文件：

禁止任何未经授权的个人或组织以任何形式将本程序及其附属资料、创新、创意、架构设计、算法、衍生作品等用于任何商业目的、盈利活动、各类竞赛(比赛)、直播教学、录播教学、线下课程、书籍编写、教材编写、会议、培训、公益活动、项目课题、毕业设计、毕业论文、学术论文等。

本程序由版权持有人和贡献人“按原样”提供，不提供任何明示或暗示担保，包括但不局限于对适销性和特定用途适合性的暗示担保。在任何情况下，版权持有人或贡献人对因使用本程序而导致的任何直接、间接、附带、特殊、典型或后果性损害（包括但不限于购买替代商品或服务；使用损失、数据丢失或利润损失；业务中断）不承担任何责任，无论其如何产生，也不论其责任理论为何，无论是合同、严格责任还是侵权（包括疏忽或其他），即使已告知此类损害的可能性。

English
All rights reserved. Licensed under the GPL 2.0 (the "License"). You may NOT use this file except in compliance with the License and the following terms:

IT IS PROHIBITED FOR ANY UNAUTHORIZED PERSON OR ENTITY TO USE THIS PROGRAM AND ITS ANCILLARY DATA, INNOVATIONS, CONCEPTS, ARCHITECTURE DESIGN, ALGORITHMS, DERIVED WORKS, ETC., IN ANY FORM FOR COMMERCIAL PURPOSES, PROFIT-MAKING ACTIVITIES, VARIOUS COMPETITIONS (CONTESTS), LIVE TEACHING, PRE-RECORDED LESSONS, OFFLINE COURSES, BOOK WRITING, CONFERENCES, TRAININGS, PUBLIC WELFARE ACTIVITIES, PROJECTS, TOPICS, GRADUATION DESIGNS, DISSERTATIONS, THESES, AND OTHER APPLICATIONS.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "ohos_init.h" 
#include "cmsis_os2.h" 
#include "ohos_types.h"
#include "stdio.h" 
#include "stdlib.h"
#include "string.h"
#include "time.h"
#include "unistd.h"
 

#include "iot_gpio.h"   // OpenHarmony HAL API：IoT硬件设备操作接口-GPIO
#include "iot_gpio_ex.h" 

#include "cJSON.h"    

//#include "hi_reset.h"            // 重启指令
#include "json_checker.h" 
 
#include "iot_crc16.h"          // 需要 crc16 校验

#include "uart_task.h"          // 需要 uart_write, set_report_open, read_hi3861_version
#include "mqtt_down.h"           //    

#include "soc_osal.h"
#include "errcode.h"


// LED灯的状态
enum LedState {
    ON = 0,
    OFF,
    SPARK,
};
enum LedState g_ledState = OFF; 

// 初始化 GPIO
void Gpio_Init(void){
    Gpio_Init();   
    IoSetFunc(IOT_IO_NAME_GPIO_9, IOT_IO_FUNC_GPIO_9_GPIO);       // 复用引脚为 GPIO  
    IoTGpioSetDir(IOT_IO_NAME_GPIO_9, IOT_GPIO_DIR_OUT);             // 设置为输出
    
    IoSetFunc(IOT_IO_NAME_GPIO_5, IOT_IO_FUNC_GPIO_9_GPIO); // ？？ 9
    IoTGpioSetDir(IOT_IO_NAME_GPIO_5, IOT_GPIO_DIR_IN); 
    IoSetPull(IOT_IO_NAME_GPIO_5, IOT_IO_PULL_UP); 
} 

// 下发命令控制 led 灯
int LED_ON(char *off_on)  { 
    if(strcmp(off_on, "ON")==0){
        IoTGpioSetOutputVal(IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE0);    //打开LED8灯
         
        g_ledState = ON;
        //printf(">>> LED turn ON <<<\n");  
    }
    else if(strcmp(off_on, "OFF")==0){
        IoTGpioSetOutputVal(IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE1);    //关闭LED8灯
        g_ledState = OFF;
        //printf(">>> LED turn OFF <<<\n");  
    }
    return 1;
}

// LED闪烁，cnt为次数，tm为每次秒数
void LED_Spark(int cnt, int tm)  {
    for (int i = 0; i < cnt; i++){
        IoTGpioSetOutputVal(IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE0);    //打开
        osDelay(tm*100);
        
        IoTGpioSetOutputVal(IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE1);    //关闭 
        osDelay(tm*100);
    }
    g_ledState = OFF;
} 

// 软重启设备 reset
void Soft_Reboot(void){ 
    //hi_hard_reboot(5);
}

// 安装高度查询
void Query_Height(void){
     
}


// 设置安装高度
void Set_Height(char* valuestring){
     
}

// 查询跌倒时长
void Query_FallTime(void){
     
}


// 设置跌倒时长
void Set_FallTime(char* valuestring){
    
}

// 上位机查询跌倒状态
void Query_Falling(void){
     
}


// 上位机查询人体距离
void Query_Distance(void){
     
}


// 上位机查询人体存在与否
void Query_Presence(void){
    unsigned char *write_cmd = NULL;     // 需要写入串口的数据 
    write_cmd = malloc(32);  
    memset(write_cmd, 0, 32);            // 每次都置0

    // 53 59 80 81 00 01 0F BD (189) 54 43 
    write_cmd[0] = 0x53;
    write_cmd[1] = 0x59;
    write_cmd[2] = 0x80;
    write_cmd[3] = 0x81;
    write_cmd[4] = 0x00;
    write_cmd[5] = 0x01;   
    // 6,7
    write_cmd[6] = 0x0F;
    write_cmd[7] = 0xBD;

    write_cmd[8] = 0x54;
    write_cmd[9] = 0x43;

    radar_write(write_cmd, 10);         // 写入OK，能正确收到回显报文
    printf("=@= write uart [80 81] \r\n");

    // 释放内存
    free(write_cmd);
}


// 上位机查询雷达固件版本
void Radar_Version(void){
    unsigned char *write_cmd = NULL;     // 需要写入串口的数据 
    write_cmd = malloc(32);  
    memset(write_cmd, 0, 32);            // 每次都置0
 
    // 53 59 02 A4 00 01 0F 62 (98) 54 43  
    write_cmd[0] = 0x53;
    write_cmd[1] = 0x59;
    write_cmd[2] = 0x02;
    write_cmd[3] = 0xA4;
    write_cmd[4] = 0x00;
    write_cmd[5] = 0x01;   
    // 6,7
    write_cmd[6] = 0x0F;
    write_cmd[7] = 0x62;

    write_cmd[8] = 0x54;
    write_cmd[9] = 0x43;

    radar_write(write_cmd, 10);         // 写入OK，能正确收到回显报文
    printf("=@= write uart [02 A4] \r\n");

    // 释放内存
    free(write_cmd);
} 

// 查询安装睡眠检测开关
void Query_Sleep(void){
    
}


// 设置睡眠检测开关
void Set_Sleep(char* valuestring){
     
}


// 查询入床、离床
void Query_Bed(void){
    
} 

// 上位机查询睡眠统计分析
void Query_SleepStat(void){
     
}
 

/*=====================================
//  指令解析方法   
//===================================*/

// 解析接收到的数据 static
int parseReceivedJson(const uint8_t *src) {
    printf("<<< rece json: %s \r\n", src);  
    uint8_t data[1024];
    memset(data, 0, 1024);
    char *p = strrchr((char *)src, '}');
    size_t n = strlen((char *)src) - strlen(p+1); 
    memcpy(data, src, n); 
	//printf("+++ right json: %s \r\n", data);  

    if(json_check((char *)data)==-1){
        printf("=!= json structure error. \r\n");  
        return -1;
    }
    
	cJSON* cjson = NULL; 
    cJSON* service_id = NULL;
    cJSON* command_name = NULL;
    cJSON* paras = NULL; 
    cJSON* value = NULL;

    // 解析整段JSO数据，  // 引发设备重启
    cjson = cJSON_Parse((char *)data);           
    if(cjson == NULL){
        printf("=!= parse json failed. \r\n");  
        return -1;
    }

    // 依次根据名称提取JSON数据（键值对） 
    service_id = cJSON_GetObjectItem(cjson, "service_id");
    command_name = cJSON_GetObjectItem(cjson, "command_name");
    paras = cJSON_GetObjectItem(cjson, "paras");
    value = cJSON_GetObjectItem(paras, "value");   // 从 paras 节点中解析 value
    if(value == NULL){
        return -1;
    }
    printf("### command_name: %s \n", command_name->valuestring);

    unsigned char *write_cmd = NULL;     // 需要写入串口的数据 
    write_cmd = malloc(32);  
    memset(write_cmd, 0, 32);  // 每次都置0

    // 执行指令
    if( strcmp(service_id->valuestring, MQTT_SERVICE_ID)==0 ) {

        //===== 公有指令 ======

        // 控制 LED 灯
        if(strcmp(command_name->valuestring, "LED_ON")==0){
            // {"service_id":"HumanRadar","command_name":"LED_ON","paras":{"value":"OFF"}}
            if(strlen(value->valuestring)!=0){          // 如果节点不存在，不会报错
                LED_ON(value->valuestring);         // 控制OFF, ON
            }
        }

        // 设置 wifi
        else if(strcmp(command_name->valuestring, "Set_Wifi")==0){ 
            // {"service_id":"FallingRadar","command_name":"Set_Wifi","paras":{"value":"0","ssid":"wifi","psk":"123456"}}
            cJSON* ssid = cJSON_GetObjectItem(paras, "ssid");   // 如果节点不存在，不会报错
            cJSON* psk  = cJSON_GetObjectItem(paras, "psk");    // 如果节点不存在，不会报错  

            if(strlen(ssid->valuestring)!=0 && strlen(psk->valuestring)!=0){
                //Save_Wifi(ssid->valuestring, psk->valuestring);  // 重新写入wifi参数   
            } 

            cJSON_Delete(ssid);
            cJSON_Delete(psk);
        }

        // 查询 wifi 参数
        else if(strcmp(command_name->valuestring, "Query_Wifi")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Wifi","paras":{"value":"00"}}  
            //read_wifi_param();      // 在 uart_task.h 中定义
        } 

        // 设置 mqtt
        else if(strcmp(command_name->valuestring, "Set_Mqtt")==0){ 
             cJSON* host = cJSON_GetObjectItem(paras, "host");   // 如果节点不存在，不会报错
            cJSON* port = cJSON_GetObjectItem(paras, "port");    // 如果节点不存在，不会报错  

            if(strlen(host->valuestring)!=0 && strlen(port->valuestring)!=0){
                //Save_Mqtt(host->valuestring, port->valuestring);  // 重新写入wifi参数
            } 

            cJSON_Delete(host);
            cJSON_Delete(port);
        }

        // 查询 mqtt 参数
        else if(strcmp(command_name->valuestring, "Query_Mqtt")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Mqtt","paras":{"value":"00"}}  
            //read_mqtt_param();      // 在 uart_task.h 中定义
        } 

        // 软重启设备 reset
        else if(strcmp(command_name->valuestring, "Soft_Reboot")==0){ 
            // {"service_id":"FallingRadar","command_name":"Soft_Reboot","paras":{"value":"0"}} 
            if(strlen(value->valuestring)!=0){          // 如果节点不存在，不会报错
                Soft_Reboot();                          // 重启
            } 
        }
         
        // 查询hi3861固件版本
        else if(strcmp(command_name->valuestring, "Firmware_Version")==0) { 
            // {"service_id":"FallingRadar","command_name":"Firmware_Version","paras":{"value":"00"}}  
            read_hi3861_version();      // 在 uart_task.h 中定义
        } 

        // hi3861固件升级指令
        else if(strcmp(command_name->valuestring, "Firmware_Ota")==0) { 
                cJSON* host = cJSON_GetObjectItem(paras, "host");    // 如果节点不存在，不会报错
            cJSON* port = cJSON_GetObjectItem(paras, "port");    // 如果节点不存在，不会报错  
            cJSON* url  = cJSON_GetObjectItem(paras, "url");    // 如果节点不存在，不会报错
            cJSON* pms  = cJSON_GetObjectItem(paras, "pms");    // 如果节点不存在，不会报错  

            if(strlen(host->valuestring)!=0 && strlen(port->valuestring)!=0){
                printf("### hi3861 ota: host=%s, port=%s \n\n ", host->valuestring, port->valuestring);
 
                char *args = malloc(256);
                memset(args, 0, 256); 

                strcpy(&args[0],    host->valuestring);
                strcpy(&args[64],   port->valuestring);
                strcpy(&args[72],   url->valuestring);
                strcpy(&args[136],  pms->valuestring);

                //firm_ota_start(args);   //  下载线程

                free(args);
            } 

            cJSON_Delete(host);
            cJSON_Delete(port);
            cJSON_Delete(url);
            cJSON_Delete(pms);  
        } 

        // 查询radar固件版本
        else if(strcmp(command_name->valuestring, "Radar_Version")==0) { 
            // {"service_id":"FallingRadar","command_name":"Radar_Version","paras":{"value":"00"}} 
            // 53 59 02 A4 00 01 0F 62 (98) 54 43 
            //Radar_Version();
        } 

        // radar固件升级指令
        else if(strcmp(command_name->valuestring, "Radar_Ota")==0) { 
         
            cJSON* host = cJSON_GetObjectItem(paras, "host");    // 如果节点不存在，不会报错
            cJSON* port = cJSON_GetObjectItem(paras, "port");    // 如果节点不存在，不会报错  
            cJSON* url = cJSON_GetObjectItem(paras, "url");    // 如果节点不存在，不会报错
            cJSON* pms = cJSON_GetObjectItem(paras, "pms");    // 如果节点不存在，不会报错  

            if(strlen(host->valuestring)!=0 && strlen(port->valuestring)!=0){ 
                 
                char *args = malloc(256);
                memset(args, 0, 256); 

                strcpy(&args[0],    host->valuestring);
                strcpy(&args[64],   port->valuestring);
                strcpy(&args[72],   url->valuestring);
                strcpy(&args[136],  pms->valuestring);

                //radar_ota_start(args);   //  下载线程

                free(args);
            } 

            cJSON_Delete(host);
            cJSON_Delete(port);
            cJSON_Delete(url);
            cJSON_Delete(pms);  
        }  
        
        // 数据上报开关
        else if(strcmp(command_name->valuestring, "Report_Open")==0) {
             
        }  

        //===== end ======
          
        // 查询安装高度：默认2.4米，跌倒雷达专有
        else if(strcmp(command_name->valuestring, "Query_Height")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Height","paras":{"value":"00"}} 
            // 53 59 06 82 00 01 0F 44 54 43 
            Query_Height();
        } 

        // 设置安装高度：默认2.4米，跌倒雷达专有
        else if(strcmp(command_name->valuestring, "Set_Height")==0) { 
            // {"service_id":"FallingRadar","command_name":"Set_Height","paras":{"value":"240"}}
            // value: 240 或 260
            // 240cm：53 59 06 02 00 02 (00 F0 A6) 54 43
            // 260cm：53 59 06 02 00 02 (01 04 BB) 54 43
            Set_Height(value->valuestring);
        } 

        // 查询跌倒时长：默认30s，跌倒雷达专有
        else if(strcmp(command_name->valuestring, "Query_FallTime")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_FallTime","paras":{"value":"00"}} 
            // 53 59 83 8C 00 01 0F CB 54 43 
            Query_FallTime();
        } 

        // 设置跌倒时长：默认30s，跌倒雷达专有
        else if(strcmp(command_name->valuestring, "Set_FallTime")==0) { 
            // {"service_id":"FallingRadar","command_name":"Set_FallTime","paras":{"value":"5-180s"}} 
            // 53 59 83 0C 00 04 (00 00 00 05) ? 54 43 
            Set_FallTime(value->valuestring);
        } 

        // 查询跌倒状态，跌倒雷达专有
        else if(strcmp(command_name->valuestring, "Query_Falling")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Falling","paras":{"value":"00"}}
            Query_Falling();  
        }

        //===== end ======

        //===== 睡眠雷达专有 ======

        // 查询睡眠检测开关
        else if(strcmp(command_name->valuestring, "Query_Sleep")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Sleep","paras":{"value":"00"}} 
            // 53 59 84 80 00 01 0F C0() 54 43 
            Query_Sleep();
        } 

        // 设置睡眠检测开关
        else if(strcmp(command_name->valuestring, "Set_Sleep")==0) { 
            // {"service_id":"FallingRadar","command_name":"Set_Sleep","paras":{"value":"00"}} 
            // 开：53 59 84 00 00 01 01() 32() 54 43 
            // 关：53 59 84 00 00 01 00() 31() 54 43 
            Set_Sleep(value->valuestring);
        } 

        // 查询入床、离床
        else if(strcmp(command_name->valuestring, "Query_Bed")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Bed","paras":{"value":"00"}} 
            // 53 59 84 81 00 01 0F C1() 54 43 
            Query_Bed();
        } 

        // 查询睡眠統計分析
        else if(strcmp(command_name->valuestring, "Query_SleepStat")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_SleepStat","paras":{"value":"00"}}  
            Query_SleepStat();
        } 

        // 查询人体距离
        else if(strcmp(command_name->valuestring, "Query_Distance")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Distance","paras":{"value":"00"}} 
            // 53 59 80 84 00 01 0F C0() 54 43 
            Query_Distance();
        } 

        // 查询人体存在
        else if(strcmp(command_name->valuestring, "Query_Presence")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Presence","paras":{"value":"00"}} 
            // 53 59 80 81 00 01 0F BD (189) 54 43 
            Query_Presence();   
        } 

        // ===== ws2812

        // 设置 lamp 感应参数
        else if(strcmp(command_name->valuestring, "Set_Person")==0){ 
            // {"service_id":"FallingRadar","command_name":"Set_Person","paras":{"value":"0","period":"123300800","grade":"20406080", "pm1": "0"}}
            cJSON* period = cJSON_GetObjectItem(paras, "period");   // 如果节点不存在，不会报错
            cJSON* grade  = cJSON_GetObjectItem(paras, "grade");    // 如果节点不存在，不会报错  
            cJSON* pm1  = cJSON_GetObjectItem(paras, "pm1");    // 如果节点不存在，不会报错  

            if(strlen(period->valuestring)!=0 && strlen(grade->valuestring)!=0){
                //Save_Person(period->valuestring, grade->valuestring, pm1->valuestring);   // 先写入nv参数  
                //open_induct();                                          // 再重新读取

                //read_person_param();      // 在 uart_task.h 中定义
            } 

            cJSON_Delete(period);
            cJSON_Delete(grade);
        }

        // 查询 lamp 感应参数
        else if(strcmp(command_name->valuestring, "Query_Person")==0) { 
            // {"service_id":"FallingRadar","command_name":"Query_Person","paras":{"value":"00"}}  
            //read_person_param();      // 在 uart_task.h 中定义
        } 

        // 开、关 ws2812 灯珠
        else if(strcmp(command_name->valuestring, "Open_Lamp")==0){ 
            // {"service_id":"FallingRadar","command_name":"Open_Lamp","paras":{"value":"0","light":"1"}}
            cJSON* light = cJSON_GetObjectItem(paras, "light");   // 如果节点不存在，不会报错 

            if(strlen(light->valuestring)!=0 ){
                //open_lamp(light->valuestring);   
            } 

            cJSON_Delete(light); 
        }

        // 开、关 ws2812 呼吸灯效果
        else if(strcmp(command_name->valuestring, "Open_Breath")==0){ 
            // {"service_id":"FallingRadar","command_name":"Open_Breath","paras":{"value":"0","light":"1","delay":"250" }}
            cJSON* light = cJSON_GetObjectItem(paras, "light");   // 如果节点不存在，不会报错 
            cJSON* delay  = cJSON_GetObjectItem(paras, "delay");    // 如果节点不存在，不会报错  

            if(strlen(light->valuestring)!=0 && strlen(delay->valuestring)!=0 ){
                // ws2812支持呼吸灯效果（ws2835不支持）
                //open_breath(light->valuestring, delay->valuestring);   
            } 

            cJSON_Delete(light); 
            cJSON_Delete(delay); 
        }


        //===== end ======

    }
	else {
		printf("=!= parse json error. \r\n");
	}
    //(void)service_id; 

    // 释放内存
    free(write_cmd);

    cJSON_Delete(value);
    cJSON_Delete(paras);
    cJSON_Delete(command_name);
    cJSON_Delete(service_id);
    cJSON_Delete(cjson);

    return 1;
}
